package com.elinshaw.netty4.config

import groovy.util.logging.Slf4j
import io.netty.bootstrap.ServerBootstrap
import io.netty.channel.*
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.SocketChannel
import io.netty.channel.socket.nio.NioServerSocketChannel
import io.netty.handler.logging.LogLevel
import io.netty.handler.logging.LoggingHandler

import javax.annotation.PostConstruct
import javax.annotation.PreDestroy

@Slf4j
abstract class NettyServerTemplate {

    final private EventLoopGroup bossGroup = new NioEventLoopGroup()
    final private EventLoopGroup workerGroup = new NioEventLoopGroup()

    abstract protected ChannelHandler[] createHandlers()

    abstract int getPort()

    abstract String getName()

    @PostConstruct
    void start() throws Exception {
        ServerBootstrap serverBootstrap = new ServerBootstrap()
        serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                .handler(new LoggingHandler(LogLevel.INFO))
                .option(ChannelOption.SO_BACKLOG, 128)
                .option(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
                .childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE)
                .childOption(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline channelPipeline = socketChannel.pipeline()
                        channelPipeline.addLast(new LoggingHandler(LogLevel.INFO))
                        ChannelHandler[] handlers = createHandlers()
                        for (ChannelHandler handler : handlers) {
                            channelPipeline.addLast(handler)
                        }
                    }
                })
        ChannelFuture channelFuture = serverBootstrap.bind(getPort()).sync()
        log.info("服务[" + getName() + "]启动完毕，监听端口[" + getPort() + "]")
        channelFuture.channel().closeFuture().sync()
    }

    @PreDestroy
    void stop() {
        bossGroup.shutdownGracefully().syncUninterruptibly()
        workerGroup.shutdownGracefully().syncUninterruptibly()
        log.info("服务[{" + getName() + "}]关闭")
    }


}
